package com.eureka.baseredis.demo;

import com.eureka.bclass.util.DateUtil;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;

import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * @Description: 可重入锁
 * @Author: lixing
 * @Date: 2021/7/10 17:19
 */
public class ReentrantLockDemo {
    public static RedissonClient redissonClient;

    static {
        Config config = new Config();
        // Redis单节点模式
        SingleServerConfig singleServerConfig = config.useSingleServer();
        singleServerConfig.setPassword("LI1234redis!");
        singleServerConfig.setAddress("redis://1.116.1.203:6379");
        singleServerConfig.setDatabase(0);
        // 客户端实例
        redissonClient = Redisson.create(config);
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = new ThreadPoolExecutor(
                10,
                100,
                30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(100),
                new ThreadPoolExecutor.CallerRunsPolicy());
        /*
         * 幂等：
         * 1、通过分布式锁过滤掉短时间内（假设当前业务执行耗时N秒，则N秒内的重复请求都会被过滤掉，但N秒之后的重复请求并不会被过滤）的重复请求
         * 2、添加数据时，设置主键、联合主键约束，防止重复数据的产生
         */
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    RLock rLock = redissonClient.getLock("rLock");
                    boolean res = false;
                    try {
                        // 尝试取锁
                        // 取锁超时时间1,单位为秒
                        // 取锁成功后，锁的有效期30，单位为秒（如果业务提前执行完毕也会提前释放锁），并开启后台线程（后台线程每隔10秒会检测持有的锁是否存在，存在的话就重置锁的有效期为30秒）
                        res = rLock.tryLock(1, 30, TimeUnit.MILLISECONDS);
                        if (res) {
                            System.out.println(DateUtil.dateToDateTimeCharacter(new Date()) + " " + Thread.currentThread().getName()+" 拿到锁，正在执行业务代码。。。。");
                        } else {
                            System.out.println(DateUtil.dateToDateTimeCharacter(new Date()) + " " + Thread.currentThread().getName()+" 超时，未拿到锁");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if(rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                            rLock.unlock();
                        }
                    }
                }
            });
        }

//        executorService.shutdown();

        //
        //
//        redissonClient.shutdown();
    }
}
